package com.taxi.comm.server.mina.filter;

import java.net.SocketAddress;
import java.util.Date;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.filterchain.IoFilter.NextFilter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.WriteRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//import com.taxi.comm.business.service.ReturnCode;
//import com.taxi.comm.message.Response;

/**
 * The session process filter which handles the session idle event, server 
 * exceptions and log informations.
 * 
 * Note: this filter should be used directly after the ExecutorFilter which holds a
 * OrderedThreadPoolExecutor.
 * 
 * @author Watertao
 *
 */
public class SessionProcessFilter extends IoFilterAdapter {

	private static final Logger log = LoggerFactory.getLogger(
			SessionProcessFilter.class);
	
    /**
     * When a client connection is accepted, we log the info. 
     * Stop the event delivery to the next filter.
     */
    public void sessionCreated(NextFilter nextFilter, IoSession session)
            throws Exception {
        
    	SocketAddress remoteAddr = session.getRemoteAddress();
    	log.debug("Request from {}", remoteAddr);
    	
    	//nextFilter.sessionCreated(session);
    }

    /**
     * In TCP/IP socket, session create event is almost the same as session opened 
     * event. 
     * We did nothing here but stop to deliver the event to the next filter.
     */
    public void sessionOpened(NextFilter nextFilter, IoSession session)
            throws Exception {
        //nextFilter.sessionOpened(session);
    }

    /**
     * When the connection is closed (whatever closed by the server ,the client or 
     * network exception). 
     * We log the information and stop to deliver the event.
     */
    public void sessionClosed(NextFilter nextFilter, IoSession session)
            throws Exception {
    	
    	log.debug("Session[{}] closed.", session.getId());
    	
        //nextFilter.sessionClosed(session);
    }

   /**
    * If no data could be read from client for more than 5 seconds (this could be configured
    * in configuration file), the session will be closed to release the resources.
    * But if the request is already begin to process (means the request has been merged, 
    * decoded, parsed and leave it to the handler), the idle event will be ignored, because
    * we do not want to interrupt the process as it is already consumed our computer resource.
    * 
    */
    public void sessionIdle(NextFilter nextFilter, IoSession session,
            IdleStatus status) throws Exception {
    	
    	
    	// filter the write idle event
    	if (status.equals(IdleStatus.WRITER_IDLE)) {
    		log.trace("Ignore write idle event.");
    		return;
    	}
    	
    	// the idle event will be generated every 5 seconds, more and more events will be
    	// add to the work queue. After the process of handler is over, these events will
    	// be processed one by one, if the session is already closed, we ignore the events.
    	if (session.isClosing() || !session.isConnected()) {
    		log.trace("Session[{}] is closing or closed, ignore the idle[{}] event.",
    				session.getId(), status.toString());
    		return;
    	}
    	
    	// If the request has began to process, we ignore the idle event.
    	if (session.getAttribute("START_PROCESS") != null) {
    		log.trace("Business process already started, ignore the idle event.");
    		return;
    	}
    	
    	//log.warn("Session[{}] idle, close the session.", session.getId());
    	//session.close(true);
    	
        //nextFilter.sessionIdle(session, status);
    }
    
    /**
     * Print out the original data as HEX format.
     * If a request was sent as 2 parts, the data will be printed 2 times.
     * In the protocolCodecFilter, the whole message will be printed again.
     */
    @Override
    public void messageReceived(NextFilter nextFilter, IoSession session,
            Object message) throws Exception {
    	
    	log.debug("Received data: " + message);
        nextFilter.messageReceived(session, message);
    }
    
    
    /**
     * Print out the byte stream as HEX format which sent to the client.
     */
    @Override
    public void filterWrite(NextFilter nextFilter, IoSession session,
            WriteRequest writeRequest) throws Exception {
    	log.debug("Sent data: " + writeRequest.getMessage());
        nextFilter.filterWrite(session, writeRequest);
    }

    /**
     * Exceptions that could not be handled by the handler will be processed here.
     * 
     * Here we just log the exception stack.
     * and return a internal server error response to the client.
     * and then close the connection after the response is flushed.
     */
    @Override
    public void exceptionCaught(NextFilter nextFilter, IoSession session,
            Throwable cause) throws Exception {
    	
		log.error("Exception", cause);
		
		if (!session.isClosing() && session.isConnected()) {
			/*Response response = new Response();
			response.getCommResponse().setSystime(new Date());
			response.getCommResponse().setResult(ReturnCode.errInternalServer.getRetCode());
			response.getCommResponse().setMsg(ReturnCode.errInternalServer.getDescription());
			
			session.write(response);*/
			
			//log.debug("Close session[{}].", session.getId());
			//session.close(false);
		}
		
    }
    
}
